//
//  JimDelightHashTable2.cpp
//  CollectionTest
//
//  Created by Dusan Vujosevic on 2013-10-27.
//  Copyright (c) 2013 Suavetech. All rights reserved.
//

#include "JimDelightHashTable2.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>

JimDelightHashTable2::JimDelightHashTable2(size_t elementCountHint):
	CollectionBase(elementCountHint), _haveZero(false), _defaultBucketSize(5), _tableSize(elementCountHint)
{
	createTable();
	size_t bitsNeeded = (size_t)log2f(elementCountHint);
	_mask = ~(~0 << bitsNeeded);
}

JimDelightHashTable2::~JimDelightHashTable2()
{
	destroyTable();
}

void JimDelightHashTable2::reset()
{
	destroyTable();
	createTable();
}

void JimDelightHashTable2::createTable()
{
	_table = (elemType**)malloc(sizeof(elemType*) * _tableSize);
	memset(_table, 0, sizeof(elemType*) * _tableSize);
}

void JimDelightHashTable2::destroyTable()
{
	for(size_t u = 0; u < _tableSize; u++)
	{
		if(_table[u] != NULL)
			free(_table[u]);
	}
	free(_table);
	_table = NULL;
}

void JimDelightHashTable2::loadElements(const void* randBytes, size_t elemCount)
{
	elemType* randElem = (elemType*)randBytes;
	for(size_t u = 0; u < elemCount; u++)
	{
		elemType elem = *randElem++;
		if(elem == (elemType)0)
		{
			_haveZero = true;
			continue;
		}
		size_t hashVal = hash(elem);
		elemType* arr = _table[hashVal];
		if(arr == NULL)
		{
			_table[hashVal] = (elemType*)malloc(sizeof(elemType) * _defaultBucketSize);
			_table[hashVal][0] = elem;
			_table[hashVal][1] = (elemType)0;
		}
		else
		{
			// Count the number of elements and search for our element
			size_t elemBucketCount = 0;
			while(*arr != (elemType)0)
			{
				if(*arr == elem)
					return; // do nothing, we already have the element
				elemBucketCount++;
				arr++;
			}
			size_t allocatedCount = ((elemBucketCount / _defaultBucketSize) + 1) * _defaultBucketSize;
			if(allocatedCount <= elemBucketCount + 1)
			{
				// Not enough space, reallocate
				_table[hashVal] = (elemType*)realloc(_table[hashVal], (allocatedCount + _defaultBucketSize) * sizeof(elemType));
				arr = _table[hashVal];
			}
			arr[elemBucketCount] = elem;
			arr[elemBucketCount + 1] = (elemType)0;
		}
	}
}

bool JimDelightHashTable2::findElement(elemType elem)
{
	if(elem == (elemType)0)
	{
		return _haveZero;
	}
	else
	{
		size_t hashVal = hash(elem);
		elemType* arr = _table[hashVal];
		if(arr != NULL)
		{
			while(*arr != (elemType)0)
			{
				if(*arr == elem)
					return true;
				else
					arr++;
			}
			return false;
		}
		else
			return false;
	}
}

